package com.bosicloud.cmb.ibp.api.manager.component;

import com.bosicloud.cmb.ibp.api.manager.commom.constant.IbpApiStatus;
import com.bosicloud.cmb.ibp.api.manager.commom.constant.StageStatus;
import com.bosicloud.cmb.ibp.api.manager.commom.constant.SubscribeApiStatus;
import com.bosicloud.cmb.ibp.api.manager.commom.model.*;
import com.bosicloud.cmb.ibp.api.manager.commom.vo.IbpApiVO;
import com.bosicloud.cmb.ibp.api.manager.dao.IbpApiStageMapper;
import com.bosicloud.cmb.ibp.api.manager.service.ApimgmtService;
import com.bosicloud.cmb.ibp.aws.adapter.commom.dto.CreateApiResultDTO;
import com.bosicloud.cmb.ibp.aws.adapter.commom.dto.DeleteApiResultDTO;
import com.bosicloud.cmb.ibp.aws.adapter.commom.dto.DeployApiResultDTO;
import com.bosicloud.cmb.ibp.aws.adapter.commom.dto.SubscribeApiResultDTO;
import com.bosicloud.cmb.ibp.commom.dto.exchange.ExchangeAction;
import com.bosicloud.cmb.ibp.commom.dto.exchange.ExchangeMessage;
import com.bosicloud.cmb.ibp.commom.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;


/**
 * @author Jack Peng
 */
@Component
@Slf4j
public class MessageExecutor {

    @Autowired
    private ApimgmtService apimgmtService;

    @Autowired
    private IbpApiStageMapper ibpApiStageMapper;

    public void receiveLogic(ExchangeMessage payload) {
        switch (payload.getAction()) {
            case ExchangeAction.CREATE_API:
                createApi(payload);
                break;
            case ExchangeAction.DEPLOY_KEY:
                deployApi(payload);
                break;
            case ExchangeAction.SUBSCRIBE_KEY:
                subscribeApi(payload);
                break;
            case ExchangeAction.UN_SUBSCRIBE_KEY:
                unSubscribeApi(payload);
                break;
            case ExchangeAction.DELETE_API_KEY:
                cascadeDeleteApi(payload);
                break;
            default:
                break;

        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void createApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        CreateApiResultDTO apiResultDTO = JsonUtil.parse(toJson, CreateApiResultDTO.class);
        final int apiId = Integer.parseInt(apiResultDTO.getApiId());
        final Boolean isSuccess = apiResultDTO.getIsSuccess();
        final String keyId = apiResultDTO.getKeyId();
        log.info("###创建API,apiId:{},后接受到结果消息为:{}", apiId, toJson);
        recordFailMessageLogic(apiId, apiResultDTO.getErrorMessage(), payload.getAction(), isSuccess, "");
        //更新API状态
        String currentStatus = (StringUtils.isNotEmpty(keyId) && isSuccess) ? IbpApiStatus.SUCCESS : IbpApiStatus.FAIL;
        Integer record = apimgmtService.updateIbpApi(IbpApi
                .builder()
                .id(apiId)
                .awsApiId(keyId)
                .status(currentStatus)
                .build());

        log.info("###更新API状态为 :{}.更新影响条数:{}", currentStatus, record);

        IbpApiVO ibpApiVO = apimgmtService.searchApiDetailById(apiId);
        if (IbpApiStatus.SUCCESS.equalsIgnoreCase(currentStatus)) {
            apimgmtService.searchUserApiKeyListByUserId(ibpApiVO.getCreateUser())
                    .forEach(rs -> {
                        IbpApiStage apiStage = ibpApiStageMapper.selectOne(IbpApiStage.builder()
                                .apiId(apiId)
                                .stage(rs.getEnv())
                                .status(StageStatus.PENDING)
                                .build());
                        if (Objects.isNull(apiStage)) {
                            //初始化stage为PENDING
                            apimgmtService.insertIbpApiStage(IbpApiStage
                                    .builder()
                                    .apiId(apiId)
                                    .stage(rs.getEnv())
                                    .status(StageStatus.PENDING)
                                    .build());
                            log.info("###初始化 IbpApiStage 完毕,apiId:{},env:{}", apiId, rs.getEnv());
                        }
                    });
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deployApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        final DeployApiResultDTO resultDTO = JsonUtil.parse(toJson, DeployApiResultDTO.class);
        final int apiId = Integer.parseInt(resultDTO.getApiId());
        final String deployId = resultDTO.getDeployId();
        final String stage = resultDTO.getStage();
        log.info("###部署API,apiId:{},接受到的结果消息:{}", apiId, toJson);
        //#TODO 失败的是否允许重复部署?
        IbpApiStage ibpApiStage = ibpApiStageMapper.select(IbpApiStage
                .builder()
                .apiId(apiId)
                .stage(stage)
                .build())
                .stream()
                .filter(rs -> (Objects.equals(stage, rs.getStage()) && Objects.equals(StageStatus.SUCCESS, rs.getStatus())))
                .findAny()
                .orElse(null);
        if (Objects.nonNull(ibpApiStage)) {
            log.info("###忽略当前Stage状态操作,因为当前stage已成功部署,apiId:{},stage状态为:{}.", apiId, ibpApiStage.getStatus());
            return;
        }
        recordFailMessageLogic(apiId, resultDTO.getErrorMessage(), payload.getAction(), resultDTO.getIsSuccess(), stage);

        String currentStatus = (StringUtils.isNotEmpty(deployId) && resultDTO.getIsSuccess())
                ? StageStatus.SUCCESS
                : StageStatus.FAIL;
        //更新stage状态
        Integer stageRecord = apimgmtService.updateIbpApiStage(IbpApiStage
                .builder()
                .apiId(apiId)
                .awsApiId(resultDTO.getAwsApiId())
                .endpoint(resultDTO.getEndpoint())
                .stage(stage)
                .deployId(deployId)
                .invokeUrl(resultDTO.getInvokeUrl())
                .status(currentStatus)
                .build());
        log.info("###更新 IbpApiStage 状态为:{}.更新条数:{}", currentStatus, stageRecord);

        if (resultDTO.getIsSuccess()) {
            Integer usagePlanRecord = apimgmtService.insertIbpApiUsagePlan(IbpApiUsagePlan
                    .builder()
                    .apiId(apiId)
                    .awsUsagePlanId(resultDTO.getUsagePlanId())
                    .env(stage)
                    .build());
            log.info("###保存 IbpApiUsagePlan 完毕.添加条数:{}", usagePlanRecord);

            List<IbpApiUsagePlan> usagePlans = apimgmtService.searchUsagePlanListByApiId(apiId);
            if (CollectionUtils.isNotEmpty(usagePlans) && usagePlans.size() >= 2) {
                Integer isPublicRecord = apimgmtService.updateIbpApi(IbpApi
                        .builder()
                        .id(apiId)
                        .isPublic(true)
                        .build());
                log.info("### 更新 isPublic 为公开 更新条数:{}", isPublicRecord);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void subscribeApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        final SubscribeApiResultDTO resultDTO = JsonUtil.parse(toJson, SubscribeApiResultDTO.class);
        final Integer apiId = Integer.parseInt(resultDTO.getApiId());
        final Integer userId = Integer.parseInt(resultDTO.getUserId());
        final String status = resultDTO.getIsSuccess() ? SubscribeApiStatus.SUCCESS : SubscribeApiStatus.FAIL;
        log.info("###订阅APi,apiId:{},接受到的消息结果:{}", apiId, toJson);
        recordFailMessageLogic(apiId, resultDTO.getErrorMessage(), payload.getAction(), resultDTO.getIsSuccess(), "");

        IbpUserConsumerApi consumerApi = apimgmtService.searchIbpUserConsumerApi(apiId, userId);
        if (Objects.nonNull(consumerApi) && !Objects.equals(SubscribeApiStatus.SUCCESS, consumerApi.getStatus())) {
            Integer record = apimgmtService.updateConsumerApi(IbpUserConsumerApi
                    .builder()
                    .apiId(apiId)
                    .userId(userId)
                    .status(status)
                    .build());
            log.info("###更新 IbpUserConsumerApi  状态为:{}.更新条数:{}", status, record);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void unSubscribeApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        final SubscribeApiResultDTO resultDTO = JsonUtil.parse(toJson, SubscribeApiResultDTO.class);
        final Integer apiId = Integer.parseInt(resultDTO.getApiId());
        log.info("###取消订阅API,apiId:{},接受到的结果消息:{}", apiId, toJson);
        recordFailMessageLogic(apiId, resultDTO.getErrorMessage(), payload.getAction(), resultDTO.getIsSuccess(), "");
        if (resultDTO.getIsSuccess()) {
            Integer record = apimgmtService.deleteConsumerApi(apiId, Integer.parseInt(resultDTO.getUserId()));
            log.info("###取消订阅,影响条数", record);
        }

    }


    @Transactional(rollbackFor = Exception.class)
    public void cascadeDeleteApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        final DeleteApiResultDTO resultDTO = JsonUtil.parse(toJson, DeleteApiResultDTO.class);
        final Integer apiId = Integer.parseInt(resultDTO.getApiId());
        log.info("###删除API,apiId:{},接受到的消息结果:{}", apiId, toJson);

        recordFailMessageLogic(apiId, resultDTO.getErrorMessage(), payload.getAction(), resultDTO.getIsSuccess(), "");

        if (resultDTO.getIsSuccess()) {
            Integer docParamsRecord = apimgmtService.deleteIbpApiDocParamsByApiId(apiId);
            log.info("###删除 IbpApiDocParamsByApiId 影响条数:{}", docParamsRecord);

            Integer docRecord = apimgmtService.deleteIbpApiDocsByApiId(apiId);
            log.info("###删除 IbpApiDocs 影响条数:{}", docRecord);

            Integer apiRecord = apimgmtService.deleteIbpApiByApiId(apiId);
            log.info("###删除 IbpApi 影响条数:{}", apiRecord);
        }

    }

    private Integer recordFailMessageLogic(int apiId, String message, String action, boolean isSuccess, String context) {

        Integer failtMsgRecord = 0;
        try {
            if (StringUtils.isNotEmpty(message) && !isSuccess) {
                failtMsgRecord = apimgmtService.insertIbpApiAwsFailtMsg(IbpApiAwsFailtMsg
                        .builder()
                        .apiId(apiId)
                        .bizType(action)
                        .msg(message)
                        .context(context)
                        .build());
                log.info("### 记录apiId:{},失败消息,插入数据条数,:{}", apiId, failtMsgRecord);
            }
        } catch (Exception e) {
            log.error("记录失败信息异常,异常信息:{}", e.getMessage(), e);
        }
        return failtMsgRecord;
    }
}
